﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;

using System.Windows.Shapes;

using SLARToolKit;

namespace SydUAR
{
    public partial class MainPage : UserControl
    {
        // UI Elements
        //private List<Image> puzzlePieces = new List<Image>();
        //private List<Canvas> puzzlePiecesContainers = new List<Canvas>();

        // Application root, change it to wherever the project is hosted
        private String appRoot = "http://localhost/";

        private CaptureSource captureSource;
        // A list containing all the patterns
        //private List<Marker> markers = new List<Marker>();
        Marker primaryMarker;

        // Used for image transformation
        private Matrix3D projectionMatrix;
        public Double scale { get; set; }
        public Double rotate { get; set; }

        // Detects patterns in webcam frames
        public CaptureSourceMarkerDetector arDetector { get; set; }

        public MainPage()
        {
            InitializeComponent();
        }



        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                Initialize();
               // ShowAll();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.ToString());
            }


        }

        private void Initialize()
        {
            scale = 0.4;
            rotate = 0;
            // Initializes the system default webcam as the frame-source
            // And sets the image quality to the one required for our app ( 640x480 )
            captureSource = new CaptureSource();
            captureSource.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
            captureSource.VideoCaptureDevice.DesiredFormat = new VideoFormat(PixelFormatType.Unknown, 640, 480, 30);

            // Initializes marker list
            //for (byte i = 1; i < 10; i++)
            //{
            //    Marker tempMarker = Marker.LoadFromResource("/Markers/" + i.ToString() + ".pat", 16, 16, 80.0, i.ToString());
            //}
            primaryMarker = Marker.LoadFromResource("Markers/Marker_L_16x16segments_80width.pat", 16, 16, 80.0, "primaryMarker");

            // Initializes image locations ( for the puzzles )
            //List<Uri> uris = new List<Uri>();
            //for (int i = 1; i < 4; i++)
            //    for (int j = 1; j < 4; j++)
            //        uris.Add(new Uri(appRoot + "/Images/" + i.ToString() + j.ToString() + ".png"));

            // Initializes the lists with the UI elements

            /*// Initializes the (yet) hidden images from the UI
            // with the images from the puzzle pieces ( the ones 
            // generated by the server )
            //for (byte i = 0; i < 9; i++)
            //{
            //    puzzlePieces[i].Source = new BitmapImage(uris[i]);
            //}*/
            //puzzle11.Source = new BitmapImage(uris[0]);
            //puzzle12.Source = new BitmapImage(uris[1]);
            //puzzle13.Source = new BitmapImage(uris[2]);

            //puzzle21.Source = new BitmapImage(uris[3]);
            //puzzle22.Source = new BitmapImage(uris[4]);
            //puzzle23.Source = new BitmapImage(uris[5]);

            //puzzle31.Source = new BitmapImage(uris[6]);
            //puzzle32.Source = new BitmapImage(uris[7]);
            //puzzle33.Source = new BitmapImage(uris[8]);

            // Add pattern detector
            arDetector = new CaptureSourceMarkerDetector(captureSource, 1, 4000, new List<Marker> { primaryMarker });
            AttachAREvent();

            projectionMatrix = Matrix3DFactory.CreatePerspectiveFieldOfViewRH(0.7, viewportContainer.Width / viewportContainer.Height, 1.0, 4000.0);
            this.DataContext = this;
        }

        /// <summary>
        /// Checks for detected patterns in the webcam frames
        /// </summary>
        private void AttachAREvent()
        {

            var dispatcher = Application.Current.RootVisual.Dispatcher;
            arDetector.MarkersDetected += (s, e) =>
                {


                    // Stores any detected pattern results
                    var detectedResults = e.DetectionResults;
                    // The AR detector creates a projection matrix
                    // based on the camera position
                    projectionMatrix = arDetector.Projection;


                    // Change the event thread from background to UI 
                    dispatcher.BeginInvoke(() =>
                        {

                            WriteableBitmap markerHighlight = null;
                            // If we get at least one result from the arDetector
                            // apply the transformations needed to 
                            // display them on the screen
                            // else hide all the images ( puzzle pieces )
                            if (detectedResults.HasResults)
                            {
                                testing.Text = "we have";
                                ApplyTransformations(detectedResults);
                                markerHighlight = new WriteableBitmap(e.BufferWidth, e.BufferHeight);
                                
                                foreach (var r in detectedResults)
                                {
                                    markerHighlight.DrawQuad((int)r.Square.P1.X, (int)r.Square.P1.Y,
                                                    (int)r.Square.P2.X, (int)r.Square.P2.Y,
                                                    (int)r.Square.P3.X, (int)r.Square.P3.Y,
                                                    (int)r.Square.P4.X, (int)r.Square.P4.Y, Colors.Red);
                                }
                                
                            }
                            else
                            {
                                HideAll();
                            }
                            viewportOverlay.Source = markerHighlight;
                        });
                };
        }

        /// <summary>
        /// Hides all the images from the UI
        /// </summary>
        private void HideAll()
        {
            puzzle11grid.Visibility = System.Windows.Visibility.Collapsed;
            puzzle12grid.Visibility = System.Windows.Visibility.Collapsed;
            puzzle13grid.Visibility = System.Windows.Visibility.Collapsed;

            puzzle21grid.Visibility = System.Windows.Visibility.Collapsed;
            puzzle22grid.Visibility = System.Windows.Visibility.Collapsed;
            puzzle23grid.Visibility = System.Windows.Visibility.Collapsed;

            puzzle31grid.Visibility = System.Windows.Visibility.Collapsed;
            puzzle32grid.Visibility = System.Windows.Visibility.Collapsed;
            puzzle33grid.Visibility = System.Windows.Visibility.Collapsed;
        }

        private void ShowAll()
        {
            puzzle11grid.Visibility = System.Windows.Visibility.Visible;
            puzzle12grid.Visibility = System.Windows.Visibility.Visible;
            puzzle13grid.Visibility = System.Windows.Visibility.Visible;

            puzzle21grid.Visibility = System.Windows.Visibility.Visible;
            puzzle22grid.Visibility = System.Windows.Visibility.Visible;
            puzzle23grid.Visibility = System.Windows.Visibility.Visible;

            puzzle31grid.Visibility = System.Windows.Visibility.Visible;
            puzzle32grid.Visibility = System.Windows.Visibility.Visible;
            puzzle33grid.Visibility = System.Windows.Visibility.Visible;
        }

        private void ApplyTransformations(DetectionResults detectedResults)
        {
            List<DetectionResult> results = new List<DetectionResult>();
            var primaryMarkers = detectedResults.Where(r => r.Marker == primaryMarker).FirstOrDefault();
            if (primaryMarkers != null)
            {
                ApplyTranformation(puzzle11grid, primaryMarkers.Transformation);
                this.puzzle11grid.Visibility = System.Windows.Visibility.Visible;
            }
            if (primaryMarker == null)
            {
                this.puzzle11grid.Visibility = System.Windows.Visibility.Collapsed;
            }
            // For earch marker in the list, checks if it is detected
            //foreach (Marker m in markers)
            //{
            //    results.Add(detectedResults.Where(r => r.Marker == m).FirstOrDefault());
            //}

            // Have to rework this...
            // PATTERN 1
            if (results[0] != null && results[0].Confidence > 0.1)
            {
                ApplyTranformation(puzzle11grid, results[0].Transformation);
                puzzle11grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[0] == null)
            {
                puzzle11grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 2
            if (results[1] != null && results[1].Confidence > 0.1)
            {
                ApplyTranformation(puzzle12grid, results[1].Transformation);
                puzzle12grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[1] == null)
            {
                puzzle12grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 3
            if (results[2] != null && results[2].Confidence > 0.1)
            {
                ApplyTranformation(puzzle13grid, results[2].Transformation);
                puzzle13grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[2] == null)
            {
                puzzle13grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 4
            if (results[3] != null && results[3].Confidence > 0.1)
            {
                ApplyTranformation(puzzle21grid, results[3].Transformation);
                puzzle21grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[3] == null)
            {
                puzzle21grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 5
            if (results[4] != null && results[4].Confidence > 0.1)
            {
                ApplyTranformation(puzzle22grid, results[4].Transformation);
                puzzle22grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[4] == null)
            {
                puzzle22grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 6
            if (results[5] != null && results[5].Confidence > 0.1)
            {
                ApplyTranformation(puzzle23grid, results[5].Transformation);
                puzzle23grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[5] == null)
            {
                puzzle23grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 7
            if (results[6] != null && results[6].Confidence > 0.1)
            {
                ApplyTranformation(puzzle31grid, results[6].Transformation);
                puzzle31grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[6] == null)
            {
                puzzle31grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 8
            if (results[7] != null && results[7].Confidence > 0.1)
            {
                ApplyTranformation(puzzle32grid, results[7].Transformation);
                puzzle32grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[7] == null)
            {
                puzzle32grid.Visibility = System.Windows.Visibility.Collapsed;
            }

            // PATTERN 9
            if (results[8] != null && results[8].Confidence > 0.1)
            {
                ApplyTranformation(puzzle33grid, results[8].Transformation);
                puzzle33grid.Visibility = System.Windows.Visibility.Visible;
            }
            else if (results[8] == null)
            {
                puzzle33grid.Visibility = System.Windows.Visibility.Collapsed;
            }
            // Finished crap
        }

        private void ApplyTranformation(Grid puzzleGrid, Matrix3D baseTransformation)
        {
            // Set up the matrices for the world transform
            var mCenterImageAtOrigin = Matrix3DFactory.CreateTranslation(-puzzleGrid.ActualWidth * 0.5, -puzzleGrid.ActualHeight * 0.5, 0.25);
            var mInvertYAxis = Matrix3DFactory.CreateScale(1, -1, 1);
            var mViewport = Matrix3DFactory.CreateViewportTransformation(viewportContainer.ActualWidth, viewportContainer.ActualHeight);
            var mRotate = Matrix3DFactory.CreateRotationZ(MathHelper.ToRadians(rotate));
            var mScale = Matrix3DFactory.CreateScale(scale);

            // Sets up the world matrix
            var mWorld = Matrix3D.Identity * 
                mCenterImageAtOrigin * 
                mInvertYAxis * 
                mRotate * 
                mScale * 
                baseTransformation;

            mWorld = Matrix3DFactory.CreateViewportProjection(mWorld, Matrix3D.Identity, projectionMatrix, mViewport);

            puzzleGrid.Projection = new Matrix3DProjection { ProjectionMatrix = mWorld };
        }
        private void fullScreen_Click(object sender, RoutedEventArgs e)
        {
            if (App.Current.Host.Content.IsFullScreen)
            {
                fullScreen.Content = "Full Screen";
            }
            else if (!App.Current.Host.Content.IsFullScreen)
            {
                fullScreen.Content = "Minimize";
            }

            App.Current.Host.Content.IsFullScreen = !App.Current.Host.Content.IsFullScreen;
        }
        private void startCapture_Click(object sender, RoutedEventArgs e)
        {
            // Initializes camera captures
            VideoBrush videoBrush = new VideoBrush();
            videoBrush.Stretch = Stretch.Uniform;
            videoBrush.SetSource(captureSource);

            // Fills the rectangle UI container with the webcam source
            webcamVideo.Fill = videoBrush;

            // Ask user for permission
            if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
            {
                captureSource.Start();
            }
            puzzleImages.Visibility = System.Windows.Visibility.Visible;
        }
    }
}
